package org.chench.extra.logsift;

import org.chench.extra.logsift.service.LogMonitor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.scheduling.annotation.EnableScheduling;
import sun.misc.Signal;

import java.io.IOException;
import java.net.InetAddress;
import java.util.Arrays;

/**
 * 应用程序启动入口类：
 * 1.开启定时任务支持
 * 2.多数据源时需要排除，否则会出循环依赖报错
 * @author chench
 * @date 2025.05.17
 */
@EnableScheduling
@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class})
public class LogsiftApplication {
    private static final Logger logger = LoggerFactory.getLogger(LogsiftApplication.class);

    public static void main(String[] args) {
        logger.info("Start ...");
        try {
            initEnv();
            // 不启动HTTP服务
            //ConfigurableApplicationContext context = new SpringApplicationBuilder(LogsiftApplication.class).web(WebApplicationType.NONE).run(args);
            // 启动HTTP服务
            ConfigurableApplicationContext context = SpringApplication.run(LogsiftApplication.class, args);
            ConfigurableEnvironment env = context.getEnvironment();
            String appName = env.getProperty("spring.application.name");
            String ip = InetAddress.getLocalHost().getHostAddress();
            String port = env.getProperty("server.port");
            String contextPath = env.getProperty("server.servlet.context-path");
            logger.info("----------------------------------------------------");
            logger.info("{} is running! ", appName);
            logger.info("http(s)://{}:{}{}", ip, port, contextPath);
            logger.info("Profile: " + Arrays.toString(env.getActiveProfiles()));
            logger.info("----------------------------------------------------");
            addShutdownHook(context);
            startup(context);
        } catch (Exception e) {
            logger.info("应用启动失败！", e);
            System.exit(-1);
        }
    }

    /**
     * 初始化环境变量
     */
    private static void initEnv() {
        // 设置日志目录
        String logDirKey = "log.dir";
        String logDirValue = System.getProperty(logDirKey);
        if (logDirValue == null || "".equals(logDirValue.trim())) {
            logDirValue = "./logs";
        }
        System.setProperty(logDirKey, logDirValue);
    }

    /**
     * 注册应用关闭钩子 <br />
     * 注：程序在执行过程中出现RuntimeException和OOM，不会触发关闭钩子执行 <br />
     *
     * @param context
     */
    private static void addShutdownHook(ApplicationContext context) {
        // 在Spring Boot应用中通过监听信号量和注册关闭钩子来实现在进程退出之前执行收尾工作
        // 监听信号量
        Signal sg = new Signal("TERM");
        Signal.handle(sg, signal -> {
            logger.info("do signal handle: {}", signal.getName());
            System.exit(0);
        });

        // 注册关闭钩子
        Runtime.getRuntime().addShutdownHook(new Thread(() -> {
            // 执行收尾工作
            // to do something
            logger.info("do something on shutdown hook");
            context.getBean(LogMonitor.class).shutdown();
        }, "ShutdownHook"));
    }

    /**
     * 启动应用
     * @param context
     */
    private static void startup(ApplicationContext context) throws IOException {
        context.getBean(LogMonitor.class).startup();
    }
}
